package com.study.studyelasticsearch.practice;

import com.study.studyelasticsearch.client.transportClient.TransportEsClient;
import com.study.studyelasticsearch.practice.bean.CompanyPosition;
import com.study.studyelasticsearch.util.es.extractor.EsAggrExtractor;
import com.study.studyelasticsearch.util.es.extractor.EsResultExtractor;
import com.study.studyelasticsearch.util.es.extractor.vo.BucketItemVo;
import com.study.studyelasticsearch.util.es.extractor.vo.BucketVo;
import com.study.studyelasticsearch.util.es.extractor.vo.MaxBucketItemVo;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.MaxAggregationBuilder;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * @author 吴宇亮 on 2022/5/20 16:51
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class PraticeCompany {

    private static final Logger log = LoggerFactory.getLogger(PraticeCompany.class);

    @Autowired
    private TransportEsClient transportClient;
    @Autowired
    private EsResultExtractor<CompanyPosition> esHitExtractor;
    @Autowired
    private EsAggrExtractor esAggrExtractor;

    // # 查询所有在广州的公司
    @Test
    public void pratice01() {
//        GET company-position/_search
//        {
//            "query": {
//                "term": {
//                    "city": {
//                        "value": "广州"
//                    }
//                }
//            }
//        }
        TransportClient client = transportClient.getClient();
        TermQueryBuilder queryBuilder = QueryBuilders.termQuery("city", "广州");
        SearchResponse searchResponse = client.prepareSearch(InitPraticeData.companyPositionIndexName).setQuery(queryBuilder).get();
        List<CompanyPosition> list = esHitExtractor.extract(searchResponse, CompanyPosition.class);
        for (CompanyPosition companyPosition : list) {
            System.out.println(companyPosition);
        }
    }

    // # 查询所有在上海或广州的公司
    @Test
    public void pratice02() {
//{
//  "query": {
//    "bool": {
//      "should": [
//        {
//          "term": {
//            "city": {
//              "value": "广州"
//            }
//          }
//        },
//        {
//          "term": {
//            "city": {
//              "value": "上海"
//            }
//          }
//        }
//      ]
//    }
//  }
//}

//{
//  "query": {
//    "terms": {
//      "city": [
//        "广州",
//        "上海"
//      ]
//    }
//  }
//}
        TransportClient client = transportClient.getClient();
        TermsQueryBuilder queryBuilder = QueryBuilders.termsQuery("city", "上海", "广州");
        SearchResponse searchResponse = client.prepareSearch(InitPraticeData.companyPositionIndexName).setQuery(queryBuilder).get();
        SearchHits hits = searchResponse.getHits();

        // bool是es的组合查询，bool有4个常用的子句：must、must_not、filter、should
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        List<QueryBuilder> should = boolQueryBuilder.should();
        should.add(QueryBuilders.termQuery("city", "广州"));
        should.add(QueryBuilders.termQuery("city", "上海"));
        SearchResponse searchResponse1 = client.prepareSearch(InitPraticeData.companyPositionIndexName).setQuery(boolQueryBuilder).get();
        SearchHits hits1 = searchResponse1.getHits();

        System.out.println();
    }

    // # 查询广州的最高工资
    @Test
    public void pratice03(){
//GET company-position/_search
//{
//  "size": 0,
//  "query": {
//    "bool": {
//      "must": [
//        {
//          "term": {
//            "city": {
//              "value": "广州"
//            }
//          }
//        }
//      ]
//    }
//  },
//  "aggs": {
//    "max_salary": {
//      "max": {
//        "field": "endSalary"
//      }
//    }
//  }
//}
        TransportClient client = transportClient.getClient();
        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("city", "广州");
        MaxAggregationBuilder aggregationBuilder = AggregationBuilders.max("广州的最高工资").field("endSalary");
        SearchResponse searchResponse = client.prepareSearch(InitPraticeData.companyPositionIndexName).setSize(0)
                .setQuery(termsQueryBuilder).addAggregation(aggregationBuilder).get();
        for (Aggregation aggregation : searchResponse.getAggregations()) {
            System.out.println(aggregation);
        }
    }

    // # 查询广州的最高工资，并且返回其他属性
    // 参考：https://blog.csdn.net/weixin_39944595/article/details/112631138
    @Test
    public void pratice04(){

    }

    // # 查询每个城市最高的工资
    // 聚和函数 aggr默认不能对text属性进行分析，因为text属性没有索引。但是可以对text.keyword进行分析，因为text.keyword有索引
    // 参考博客：https://blog.csdn.net/weixin_43744563/article/details/122560116
    @Test
    public void pratice05(){
//        "GET /study-company-position/_search\n" +
//                "{\n" +
//                "  \"size\": 0,\n" +
//                "  \"aggs\": {\n" +
//                "    \"城市\": {\n" +
//                "      \"terms\": {\n" +
//                "        \"field\": \"city.keyword\"\n" +
//                "      },\n" +
//                "      \"aggs\": {\n" +
//                "        \"最高工资\": {\n" +
//                "          \"max\": {\n" +
//                "            \"field\": \"endSalary\"\n" +
//                "          }\n" +
//                "        }\n" +
//                "      }\n" +
//                "    }\n" +
//                "  }\n" +
//                "}"
        TransportClient client = transportClient.getClient();
        SearchRequestBuilder requestBuilder = client.prepareSearch(InitPraticeData.companyPositionIndexName);
        SearchResponse searchResponse = requestBuilder.setSize(0)
                .addAggregation(AggregationBuilders.terms("城市").field("city.keyword")
                        .subAggregation(AggregationBuilders.max("最高工资").field("endSalary"))).get();
        log.info("\nGET /{}/_search \n{}", InitPraticeData.companyPositionIndexName, requestBuilder);
        System.out.println(searchResponse);

        // 提取聚类结果
        BucketVo maxSalaryGroupByCityBucket = esAggrExtractor.extract(searchResponse);
        BucketItemVo bucketItem = (BucketItemVo) maxSalaryGroupByCityBucket.getBucketItem("上海");
        if(null != bucketItem && null != bucketItem.getBucket()){
            MaxBucketItemVo maxSalary = (MaxBucketItemVo) bucketItem.getBucket().getBucketItem("最高工资");
            System.out.println(maxSalary.getValue());
        }
    }

    // # 查询每个城市每个职位最高的工资
    @Test
    public void pratice06(){
        TransportClient client = transportClient.getClient();
        SearchRequestBuilder requestBuilder = client.prepareSearch(InitPraticeData.companyPositionIndexName);
        SearchResponse searchResponse = requestBuilder.setSize(0)
                .addAggregation(AggregationBuilders.terms("城市").field("city.keyword")
                        .subAggregation(AggregationBuilders.terms("职位").field("positionName.keyword")
                                .subAggregation(AggregationBuilders.max("最高工资").field("endSalary"))))
                        .get();
        log.info("\nGET /{}/_search \n{}", InitPraticeData.companyPositionIndexName, requestBuilder);
        System.out.println(searchResponse);

        // 提取聚类结果
        BucketVo cityBucket = esAggrExtractor.extract(searchResponse);
        BucketItemVo cityBucketItem = (BucketItemVo) cityBucket.getBucketItem("上海");
        if(null != cityBucketItem && null != cityBucketItem.getBucket()){
            BucketItemVo positionBucketItem = (BucketItemVo) cityBucketItem.getBucket().getBucketItem("高级数据分析师");
            if(null != positionBucketItem && null != positionBucketItem.getBucket()) {
                MaxBucketItemVo maxSalary = (MaxBucketItemVo) positionBucketItem.getBucket().getBucketItem("最高工资");
                if(null != maxSalary){
                    Double value = maxSalary.getValue();
                    System.out.println(cityBucketItem.getKey() + " " + positionBucketItem.getKey() + " " + maxSalary.getKey() + " " + value);
                }
            }
        }
    }



}
